
export type ResExt = { ext: string }
export default class ResManager {
    private _loadedRes: Map<string, number>;
    //private _loadedExternalUrls: Map<string, number>;

    private constructor() {
        this._loadedRes = new Map();
    }
    private static _instance: ResManager;
    public static get instance() {
        if (!this._instance) {
            this._instance = new ResManager();
        }
        return this._instance;
    }
    clipsIdMap={};
    public createAnimas(id,anim:cc.Animation){
        let alta = ResManager.instance.getRes<cc.SpriteAtlas>('atlas/'+id,cc.SpriteAtlas);
        let array=alta.getSpriteFrames();
        let clips = this.clipsIdMap[id];
        if (!clips) {
            clips={};
            for (let index = 0; index < array.length; index++) {
                const element = array[index];
                let name = element.name.substring(0,2);
                if (!clips[name]) {
                    clips[name] = [];
                }
                clips[name].push(element);
            }
        }
        
        for (const key in clips) {
            let sprites = clips[key];
           let clip = cc.AnimationClip.createWithSpriteFrames(sprites, 12);//创建一组动画剪辑
           if (key.startsWith('A')) {
               clip.wrapMode = 1;
           }else{
            clip.wrapMode = 2;
           }
           anim.addClip(clip, key);
        }
    }
    public getRes<T extends cc.Asset>(url: string,type:typeof cc.Asset):T {
        return cc.resources.get<T>(url,type);
    }
    public loadPrefabAsync(url: string): cc.Node {
        let prefab = this.getRes<cc.Prefab>(url,cc.Prefab);
        let node = cc.instantiate(prefab);
        return node;
    }
    public async setSpriteImage(sprite: cc.Sprite, url: string, isRemote = false) {
        if (isRemote) {
            let ext = null;
            if (!url.endsWith('.png')) {
                ext = { ext: '.png' };
            }
            let img = await this.loadRemote<cc.Texture2D>(url, null, ext);
            sprite.spriteFrame = new cc.SpriteFrame(img);
        } else {
            sprite.spriteFrame = await this.loadRes<cc.SpriteFrame>(url);
        }
    }
    public async setSpriteImageFromAtla(sprite: cc.Sprite, atlaUrl: string, name: string) {
        let atla = await this.loadRes<cc.SpriteAtlas>(atlaUrl);
        sprite.spriteFrame = atla.getSpriteFrame(name);
    }
    public async loadPrefab(url: string): Promise<cc.Node> {
        let prefab = await this.loadRes<cc.Prefab>(url);
        let node = cc.instantiate(prefab);
        return node;
    }
    public async setAudioSource(audioSource: cc.AudioSource, url: string, isLoop = false, isRemote = false) {
        if (isRemote) {
            audioSource.clip = await this.loadRemote<cc.AudioClip>(url);
        } else {
            audioSource.clip = await this.loadRes<cc.AudioClip>(url);
        }
        audioSource.loop = isLoop;
        audioSource.play();
    }


    public async loadRemote<T extends cc.Asset>(url: string, cb?: Function, ext?: ResExt) {
        return new Promise<T>((resolve, reject) => {
            let res = cc.resources.get(url) as T;
            if (cc.isValid(res)) {
                if (cb)
                    cb(null, res);
                resolve(res);
                return;
            }
            cc.assetManager.loadRemote<T>(url, ext, (err, res) => {
                if (err) {
                    reject(err);
                    return;
                }
                if (cb)
                    cb(res);
                resolve(res);
            });
        })

    }

    public async loadRes<T extends cc.Asset>(url: string, cb?: Function) {
        return new Promise<T>((resolve, reject) => {
            let res = cc.resources.get<T>(url, );
            if (cc.isValid(res)) {
                if (cb)
                    cb(null, res);
                resolve(res);
                return;
            }
            cc.resources.load<T>(url, (err, res) => {
                if (err) {
                    reject(err);
                    return;
                }
                if (cc.isValid(res)) {
                    if (cb)
                        cb(err, res);
                    resolve(res);
                }
            });
        })

    }

    public async loadDir<T extends cc.Asset>(url: string, progressCallback?: (completedCount: number, totalCount: number) => void,
        completeCallback?: (error: Error, resource: T[]) => void) {
        return new Promise<T[]>((resolve, reject) => {
            cc.resources.loadDir<T>(url, progressCallback, (err, res:T[]) => {
                if (err) {
                    reject(err);
                    return;
                }
                if (cc.isValid(res)) {
                    if (completeCallback)
                        completeCallback(err, res);
                    resolve(res);
                }
            });
        })
    }
    public release(asset: cc.Asset) {
        if (!asset) {
            return;
        }
        asset.decRef();

    }



}